/***************************************************************************
*   Copyright (C) 2010-2011 by swkyer <swkyer@gmail.com>                  *
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
*   This program is distributed in the hope that it will be useful,       *
*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
*   GNU General Public License for more details.                          *
*                                                                         *
*   You should have received a copy of the GNU General Public License     *
*   along with this program; if not, write to the                         *
*   Free Software Foundation, Inc.,                                       *
*   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
***************************************************************************/
#ifndef __JLINKPROTOCOL_H__
#define __JLINKPROTOCOL_H__

#include "JlinkUSB.h"


/* bits return from EMU_CMD_GET_CAPS */
#define EMU_CAP_RESERVED				(1 << 0)
#define EMU_CAP_GET_HW_VERSION			(1 << 1)
#define EMU_CAP_WRITE_DCC				(1 << 2)
#define EMU_CAP_ADAPTIVE_CLOCKING		(1 << 3)
#define EMU_CAP_READ_CONFIG				(1 << 4)
#define EMU_CAP_WRITE_CONFIG			(1 << 5)
#define EMU_CAP_TRACE					(1 << 6)
#define EMU_CAP_WRITE_MEM				(1 << 7)
#define EMU_CAP_READ_MEM				(1 << 8)
#define EMU_CAP_SPEED_INFO				(1 << 9)
#define EMU_CAP_EXEC_CODE				(1 << 10)
#define EMU_CAP_GET_MAX_BLOCK_SIZE		(1 << 11)
#define EMU_CAP_GET_HW_INFO				(1 << 12)
#define EMU_CAP_SET_KS_POWER			(1 << 13)
#define EMU_CAP_RESET_STOP_TIMED		(1 << 14)
//#define EMU_CAP_RESERVED				(1 << 15)
#define EMU_CAP_MEASURE_RTCK_REACT		(1 << 16)
#define EMU_CAP_SELECT_IF				(1 << 17)
#define EMU_CAP_RW_MEM_ARM79			(1 << 18)
#define EMU_CAP_GET_COUNTERS			(1 << 19)
#define EMU_CAP_READ_DCC				(1 << 20)
#define EMU_CAP_GET_CPU_CAPS			(1 << 21)
#define EMU_CAP_EXEC_CPU_CMD			(1 << 22)
#define EMU_CAP_SWO						(1 << 23)
#define EMU_CAP_WRITE_DCC_EX			(1 << 24)
#define EMU_CAP_UPDATE_FIRMWARE_EX		(1 << 25)
#define EMU_CAP_FILE_IO					(1 << 26)
#define EMU_CAP_REGISTER				(1 << 27)
#define EMU_CAP_INDICATORS				(1 << 28)
#define EMU_CAP_TEST_NET_SPEED			(1 << 29)
#define EMU_CAP_RAWTRACE				(1 << 30)
//#define EMU_CAP_RESERVED				(1 << 31)

#define EMU_CAP_EX_RESERVED				(1 << 0)
#define EMU_CAP_EX_GET_HW_VERSION		(1 << 1)
#define EMU_CAP_EX_WRITE_DCC			(1 << 2)
#define EMU_CAP_EX_ADAPTIVE_CLOCKING	(1 << 3)
#define EMU_CAP_EX_READ_CONFIG			(1 << 4)
#define EMU_CAP_EX_WRITE_CONFIG			(1 << 5)
#define EMU_CAP_EX_TRACE				(1 << 6)
#define EMU_CAP_EX_WRITE_MEM			(1 << 7)
#define EMU_CAP_EX_READ_MEM				(1 << 8)
#define EMU_CAP_EX_SPEED_INFO			(1 << 9)
#define EMU_CAP_EX_EXEC_CODE			(1 << 10)
#define EMU_CAP_EX_GET_MAX_BLOCK_SIZE	(1 << 11)
#define EMU_CAP_EX_GET_HW_INFO			(1 << 12)
#define EMU_CAP_EX_SET_KS_POWER			(1 << 13)
#define EMU_CAP_EX_RESET_STOP_TIMED		(1 << 14)
//#define EMU_CAP_RESERVED				(1 << 15)
#define EMU_CAP_EX_MEASURE_RTCK_REACT	(1 << 16)
#define EMU_CAP_EX_SELECT_IF			(1 << 17)
#define EMU_CAP_EX_RW_MEM_ARM79			(1 << 18)
#define EMU_CAP_EX_GET_COUNTERS			(1 << 19)
#define EMU_CAP_EX_READ_DCC				(1 << 20)
#define EMU_CAP_EX_GET_CPU_CAPS			(1 << 21)
#define EMU_CAP_EX_EXEC_CPU_CMD			(1 << 22)
#define EMU_CAP_EX_SWO					(1 << 23)
#define EMU_CAP_EX_WRITE_DCC_EX			(1 << 24)
#define EMU_CAP_EX_UPDATE_FIRMWARE_EX	(1 << 25)
#define EMU_CAP_EX_FILE_IO				(1 << 26)
#define EMU_CAP_EX_REGISTER				(1 << 27)
#define EMU_CAP_EX_INDICATORS			(1 << 28)
#define EMU_CAP_EX_TEST_NET_SPEED		(1 << 29)
#define EMU_CAP_EX_RAWTRACE				(1 << 30)
#define EMU_CAP_EX_GET_CAPS_EX			(1 << 31)
#define EMU_CAP_EX_HW_JTAG_WRITE		(1 << 31)

#define HW_INFO_POWER_ENABLED			(1 << 0)
#define HW_INFO_POWER_OVERCURRENT		(1 << 1)
#define HW_INFO_ITARGET					(1 << 2)
#define HW_INFO_ITARGET_PEAK			(1 << 3)
#define HW_INFO_ITARGET_PEAK_OPERATION	(1 << 4)
#define HW_INFO_ITARGET_MAX_TIME0		(1 << 10)
#define HW_INFO_ITARGET_MAX_TIME1		(1 << 11)
#define HW_INFO_ITARGET_MAX_TIME2		(1 << 12)

#define CNT_INDEX_POWER_ON				(1 << 0)
#define CNT_INDEX_POWER_CHANGE			(1 << 1)

#define CPU_CAP_RESERVED				(1 << 0)
#define CPU_CAP_WRITE_MEM				(1 << 1)
#define CPU_CAP_READ_MEM				(1 << 2)

#define TIF_JTAG						(1 << 0)
#define TIF_SWO							(1 << 1)


/* Constants for JLink command */
#define EMU_CMD_VERSION						0x01
#define EMU_CMD_RESET_TRST					0x02
#define EMU_CMD_RESET_TARGET				0x03
#define EMU_CMD_SET_SPEED					0x05
#define EMU_CMD_GET_STATE					0x07
#define EMU_CMD_GET_UNKNOW_09				0x09
#define EMU_CMD_SET_KS_POWER				0x08
#define EMU_CMD_GET_SPEEDS					0xc0
#define EMU_CMD_GET_HW_INFO					0xc1
#define EMU_CMD_GET_COUNTERS				0xc2
#define EMU_CMD_GET_UNKNOW_C6				0xc6
#define EMU_CMD_SELECT_IF					0xc7
#define EMU_CMD_HW_CLOCK					0xc8
#define EMU_CMD_HW_TMS0						0xc9
#define EMU_CMD_HW_TMS1						0xca
#define EMU_CMD_HW_DATA0					0xcb
#define EMU_CMD_HW_DATA1					0xcc
#define EMU_CMD_HW_JTAG2					0xce
#define EMU_CMD_HW_JTAG3					0xcf
#define EMU_CMD_HW_RELEASE_RESET_STOP_EX	0xd0
#define EMU_CMD_HW_RELEASE_RESET_STOP_TIMED	0xd1
#define EMU_CMD_GET_MAX_MEM_BLOCK			0xd4
#define EMU_CMD_HW_JTAG_GET_RESULT			0xd6
#define EMU_CMD_HW_RESET0					0xdc
#define EMU_CMD_HW_RESET1					0xdd
#define EMU_CMD_HW_TRST0					0xde
#define EMU_CMD_HW_TRST1					0xdf
#define EMU_CMD_GET_UNKNOW_E6				0xe6
#define EMU_CMD_GET_CAPS					0xe8
#define	EMU_CMD_EXEC_CPU_CMD				0xea
#define	EMU_CMD_GET_UNKNOW_EB				0xeb
#define EMU_CMD_GET_CAPS_EX					0xed
#define EMU_CMD_GET_HW_VERSION				0xf0
#define EMU_CMD_WRITE_DCC					0xf1
#define EMU_CMD_READ_CONFIG					0xf2
#define EMU_CMD_WRITE_CONFIG				0xf3
#define EMU_CMD_MEASURE_RTCK_REACT			0xf6


static inline void buf_set_u16(uint8_t *buffer, uint16_t value)
{
	buffer[1] = (value >> 8) & 0xff;
	buffer[0] = (value >> 0) & 0xff;
}

static inline uint16_t buf_get_u16(const uint8_t *buffer)
{
	return (((uint32_t)buffer[1]) << 8) | (((uint32_t)buffer[0]) << 0);
}

static inline void buf_set_u32(uint8_t *buffer, uint32_t value)
{
	buffer[3] = (value >> 24) & 0xff;
	buffer[2] = (value >> 16) & 0xff;
	buffer[1] = (value >> 8) & 0xff;
	buffer[0] = (value >> 0) & 0xff;
}

static inline uint32_t buf_get_u32(const uint8_t *buffer)
{
	return (((uint32_t)buffer[3]) << 24) |
		(((uint32_t)buffer[2]) << 16) |
		(((uint32_t)buffer[1]) << 8) |
		(((uint32_t)buffer[0]) << 0);
}


typedef struct _jlink_speed
{
	uint32_t BaseFreq;				// base frequency of emulator CPU
	uint16_t MinDiv;				// min. divider of emulator CPU
} jlink_speed_t;

typedef struct _jlink_caps
{
	uint32_t caps;
	uint8_t capsex[32-4];
} jlink_caps_t;

typedef struct _jlink_state
{
	uint16_t voltage;				// VCC stored in unit mV
	uint8_t tck;					// JTAG pin TCK state.
	uint8_t tdi;					// JTAG pin TDI state.
	uint8_t tdo;					// JTAG pin TDO state.
	uint8_t tms;					// JTAG pin TMS state.
	uint8_t tres;					// JTAG pin TRES state.
	uint8_t trst;					// JTAG pin TRST state.
} jlink_state_t;

typedef struct _jlink_hwinfo
{
	uint32_t power_enabled;			// Retrieves KS power status.
									// 0x00000000: Power is off 
									// 0x00000001: Power is on
	uint32_t power_overcurrent;		// Retrieves information about why the target power was switched off.
									// 0x00000000: Everything is normal
									// 0x00000001: 2ms @ 3000mA
									// 0x00000002: 10ms @ 1000mA
									// 0x00000003: 40ms @ 400mA
	uint32_t itarget;				// Consumption of the target in mA.
	uint32_t itarget_peak;			// Peak consumption of the target in mA.
	uint32_t itarget_peak_operation;// Peak consumption of the target in mA while operating. In most cases this is the
									// same value as HW_INFO_ITARGET_PEAK.
	uint32_t itarget_max_time0;		// Max. time in ms the consumption of the target exceeded
									// HW_INFO_POWER_OVERCURRENT type 0x01.
	uint32_t itarget_max_time1;		// Max. time in ms the consumption of the target exceeded
									// HW_INFO_POWER_OVERCURRENT type 0x02.
	uint32_t itarget_max_time2;		// Max. time in ms the consumption of the target exceeded
									// HW_INFO_POWER_OVERCURRENT type 0x03.
} jlink_hwinfo_t;

typedef struct _jlink_counters
{
	uint32_t power_on;				// Retrieves the counter describing how many ms a powered target is connected.
									// The counter is reset after 24h.
	uint32_t power_change;			// Retrieves the counter describing how many times a powered target was connected
									// or disconnected.
} jlink_counters_t;

typedef struct _jlink_rtck
{
	uint32_t result;				// 0x00000000: O.K. 0x00000001: RTCK did not react on time.
	uint32_t minimum;				// Minimum RTCK reaction time in ns.
	uint32_t maximum;				// Maximum RTCK reaction time in ns.
	uint32_t average;				// Average RTCK reaction time in ns.
} jlink_rtck_t;

typedef struct _jlink_jtag_acc
{
	uint16_t numbits;				// Number of bits to transfer.
	uint8_t *tdi;					// Data for TDI. NumBytes calculates as follows: NumBytes = (NumBits + 7) >> 3
	uint8_t *tms;					// Data for TMS. NumBytes calculates as follows: NumBytes = (NumBits + 7) >> 3
	uint8_t *tdo;					// TDO data. NumBytes calculates as follows: NumBytes = (NumBits + 7) >> 3
	uint8_t result;					// Return value: 0: O.K. Everything else: Error occured.
} jlink_jtag_acc_t;

typedef struct _jlink_criteria
{
	uint16_t offset;				// Offset address where to check for criteria match.
	uint16_t mask;					// Criteria mask.
	uint16_t data;					// Criteria to match.
} jlink_criteria_t;

typedef struct _jlink_cpu_caps_cmd
{
	uint8_t device_family;			// Device family of the target CPU
	uint8_t interf;					// Target interface used to connect the emulator to the target CPU.
	uint8_t dumy1;
	uint8_t dumy2;
} jlink_cpu_caps_cmd_t;

typedef struct _jlink_config
{
	uint8_t usb_addr;				// USB-Address of the emulator. Allows usage of more than one J-Link at the same time.
	uint8_t dumy1[3];
	uint32_t ks_power;				// Kickstart power on JTAG-pin 19.
	uint32_t dumy2[2];
	uint32_t ip_addr;				// IP-Address (only for J-Link Pro).
	uint32_t ip_mask;				// Subnetmask (only for J-Link Pro).
	uint32_t dumy3;
	uint32_t mac_addr;				// MAC-Address (only for J-Link Pro).
	uint32_t dumy[56];
} jlink_config_t;

typedef struct _jlink_unknow_e6
{
	uint8_t data[32];				// FIXME
	uint8_t supp[256-32];			// FIXME
} jlink_unknow_e6_t;

typedef struct _jlink_unknow_eb
{
	uint32_t data1[2];				// FIXME
	uint32_t data2[5];				// FIXME
} jlink_unknow_eb_t;

typedef struct _jlink_unknow_c6
{
	uint32_t data1;					// FIXME
} jlink_unknow_c6_t;

typedef struct _jlink_unknow_09
{
	uint8_t data1[64];				// FIXME
	uint8_t data2[12];				// FIXME
} jlink_unknow_09_t;


// Get system information functions
JLINKUSB_API int jlinkusb_get_version(jlink_usb_t *devh, char version[0x100]);
JLINKUSB_API int jlinkusb_get_speed(jlink_usb_t *devh, jlink_speed_t *pspeed);
JLINKUSB_API int jlinkusb_get_max_mem_block(jlink_usb_t *devh, uint32_t *pmaxblock);
JLINKUSB_API int jlinkusb_get_caps(jlink_usb_t *devh, jlink_caps_t *pcaps);
JLINKUSB_API int jlinkusb_get_caps_ex(jlink_usb_t *devh, jlink_caps_t *pcaps);
JLINKUSB_API int jlinkusb_get_hw_version(jlink_usb_t *devh, uint32_t *phwver);
JLINKUSB_API int jlinkusb_get_unknow_e6(jlink_usb_t *devh, jlink_unknow_e6_t *pe6);
JLINKUSB_API int jlinkusb_get_unknow_eb(jlink_usb_t *devh, jlink_unknow_eb_t *peb);
JLINKUSB_API int jlinkusb_get_unknow_c6(jlink_usb_t *devh, jlink_unknow_c6_t *pc6);
// Get state information functions
JLINKUSB_API int jlinkusb_get_state(jlink_usb_t *devh, jlink_state_t *pstate);
JLINKUSB_API int jlinkusb_get_unknow_09(jlink_usb_t *devh, jlink_unknow_09_t *p09, int ab);
JLINKUSB_API int jlinkusb_get_hw_info(jlink_usb_t *devh, jlink_hwinfo_t *phwinfo);
JLINKUSB_API int jlinkusb_get_counters(jlink_usb_t *devh, jlink_counters_t *pcounter);
JLINKUSB_API int jlinkusb_measure_rtck_react(jlink_usb_t *devh, jlink_rtck_t *prtck);
// JTAG & Hardware functions
JLINKUSB_API int jlinkusb_reset_trst(jlink_usb_t *devh);
JLINKUSB_API int jlinkusb_set_speed(jlink_usb_t *devh, uint16_t speed);
JLINKUSB_API int jlinkusb_select_if(jlink_usb_t *devh, uint8_t subcmd, uint32_t *presp);
JLINKUSB_API int jlinkusb_set_ks_power(jlink_usb_t *devh, uint8_t onoff);
JLINKUSB_API int jlinkusb_hw_clock(jlink_usb_t *devh, uint8_t *ptdi);
JLINKUSB_API int jlinkusb_hw_tms0(jlink_usb_t *devh);
JLINKUSB_API int jlinkusb_hw_tms1(jlink_usb_t *devh);
JLINKUSB_API int jlinkusb_hw_data0(jlink_usb_t *devh);
JLINKUSB_API int jlinkusb_hw_data1(jlink_usb_t *devh);
JLINKUSB_API int jlinkusb_hw_trst0(jlink_usb_t *devh);
JLINKUSB_API int jlinkusb_hw_trst1(jlink_usb_t *devh);
JLINKUSB_API int jlinkusb_hw_jtag3(jlink_usb_t *devh, jlink_jtag_acc_t *pjtagacc);
JLINKUSB_API int jlinkusb_hw_jtag_write(jlink_usb_t *devh, jlink_jtag_acc_t *pjtagacc);
JLINKUSB_API int jlinkusb_hw_jtag_get_result(jlink_usb_t *devh, uint8_t *result);
JLINKUSB_API int jlinkusb_write_dcc(jlink_usb_t *devh);
// Target functions
JLINKUSB_API int jlinkusb_reset_target(jlink_usb_t *devh);
JLINKUSB_API int jlinkusb_hw_release_reset_stop_ex(jlink_usb_t *devh, jlink_jtag_acc_t *pjtagacc, 
												uint16_t reps, jlink_criteria_t *pcriteria);
JLINKUSB_API int jlinkusb_hw_release_reset_stop_timed(jlink_usb_t *devh, jlink_jtag_acc_t *pjtagacc,
													uint16_t timeout, jlink_criteria_t *pcriteria);
JLINKUSB_API int jlinkusb_hw_reset0(jlink_usb_t *devh);
JLINKUSB_API int jlinkusb_hw_reset1(jlink_usb_t *devh);
JLINKUSB_API int jlinkusb_get_cpu_caps(jlink_usb_t *devh, jlink_cpu_caps_cmd_t *pcapcmd, uint32_t *pcpucaps);
// Configuration functions
JLINKUSB_API int jlinkusb_read_config(jlink_usb_t *devh, jlink_config_t *pconfig);
JLINKUSB_API int jlinkusb_write_config(jlink_usb_t *devh, jlink_config_t *pconfig);


#endif /* end of __JLINKPROTOCOL_H__ */
